package com.xb.loan.cashier.biz.pay.wechat;

import com.alibaba.fastjson.JSONObject;
import com.xb.loan.cashier.biz.pay.PaymentForCharge;
import com.xb.loan.cashier.biz.pay.bean.PaymentChargeOrder;
import com.xb.loan.cashier.biz.pay.wechat.util.RandomStringGenerator;
import com.xb.loan.cashier.biz.pay.wechat.util.WeChatDeepLink;
import com.xb.loan.cashier.biz.pay.wechat.util.WeChatSignature;
import com.xb.loan.cashier.biz.pay.wechat.util.httpClient.HttpsRequestUtil;
import com.xb.loan.cashier.biz.util.XMLUtil;
import com.xb.loan.util.json.JsonUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.Map;

/**
 * 微信支付（仅充值
 * 将微信支付中的充值单独提出做成工厂方便扩展和调用
 */
public class WeChatPaymentForCharge extends PaymentForCharge {
    private static Logger log = LoggerFactory.getLogger(WeChatPaymentForCharge.class);
    
    /**
	 * 通过手机App进行充值，提交到第三方的充值订单信息（生成微信deeplink地址）
	 * 
	 * @param paymentChargeOrder 充值信息
	 * @return 跳转网关的url串
	 * @throws Exception
	 * 2016年6月3日 by lh.qiu
	 */
    @Override
	public String chargeByApp(PaymentChargeOrder paymentChargeOrder)
			throws Exception {
		// 商户号
		String channelUser = paymentChargeOrder.getChannelUser();
		// 题目
		String title = paymentChargeOrder.getTitle();
		//  明细
		String detail = paymentChargeOrder.getDetail();
		// 订单号
		String orderId = paymentChargeOrder.getOrderId();
		// 金额
		double money = paymentChargeOrder.getMoney();
		// 加密key
		String signKey = paymentChargeOrder.getSignKey();
		// json配置串
    	String jsonConfig = paymentChargeOrder.getJsonConfig();
    	// 支付地址
		String payUrl = paymentChargeOrder.getPayUrl();
		// 通知地址
		String notifyUrl = paymentChargeOrder.getNotifyUrl();
		
		// 个性化配置
		JSONObject jsonObject =  JsonUtils.fromJson(jsonConfig);
		//获取appid
        String appid = jsonObject.get("appid").toString();
        //用户IP地址，与客户端地址不同，由调用者传入
        String remoteAddr = jsonObject.getString("remoteAddr").toString();
    	
        //金额格式化
        DecimalFormat df  = new DecimalFormat("#");
        //获取prepayid
        Map<String , Object> map = new HashMap<String , Object>();
        
        //String notifyUrl = cpc.getNotifyUrl() + "/" + ccr.getPlatId() + "/" + cpc.getPayChannelId();
        
        map.put("appid", appid);
        //微信支付分配的商户号
        map.put("mch_id", channelUser);
        
        //随机字符串，不长于32位
        map.put("nonce_str", RandomStringGenerator.getRandomStringByLength(32));
        //商品或支付单简要描述
        map.put("body", title);
        //商品详情
        map.put("detail", detail);
        //商户系统内部的订单号,32个字符内
        map.put("out_trade_no", orderId);
        //订单总金额，单位为分
        map.put("total_fee", df.format(money * 100));
        //APP和网页支付提交用户端ip
        map.put("spbill_create_ip", remoteAddr);
        //接收微信支付异步通知回调地址，通知url必须为直接可访问的url，不能携带参数
        map.put("notify_url", notifyUrl);
        //交易类型
        map.put("trade_type", WeChatConst.TRADE_TYPE_WAP);
        
        //map.put("openid", openid);
        
        //对请求参数签名
        String paySign = WeChatSignature.getSign(map, signKey);
        //对请求参数签名
        map.put("sign", paySign);
        
        //请求返回xml
        //String unifiedOrderResult = new HttpsCerRequest().sendPost(payUrl + WeChatConst.TRADE_URL_UNIFIEDORDER, map);
        String postDataXML = XMLUtil.mapToXml(map);
        String unifiedOrderResult = HttpsRequestUtil.httpsRequestToString(payUrl + WeChatConst.TRADE_URL_UNIFIEDORDER, "POST", postDataXML);
        
        log.info("wechat https request:" + unifiedOrderResult);
        
        Map<String, Object> unifiedOrderMap = XMLUtil.parse(unifiedOrderResult.getBytes(WeChatConst.TRADE_CHARSET_UTF8));
        
        String return_code = (String)unifiedOrderMap.get("return_code");
        
        if(null == return_code || WeChatConst.TRADE_FAIL.equals(return_code)){
            //统一下单失败
            log.info("WeChatPayment.wapCreateDeepLink return_code:" + return_code + 
                    ",return_msg:" + unifiedOrderMap.get("return_msg"));
            return null;
        }
        
        //业务结果
        String result_code = (String)unifiedOrderMap.get("result_code");
        
        if(null == result_code || WeChatConst.TRADE_FAIL.equals(result_code)){
            //统一下单失败
            log.info("WeChatPayment.wapCreateDeepLink err_code:" + unifiedOrderMap.get("err_code") + 
                    ",err_code_des:" + unifiedOrderMap.get("err_code_des"));
            return null;
        }
        
        //微信生成的预支付回话标识，用于后续接口调用中使用，该值有效期为2小时
        String prepayid = (String)unifiedOrderMap.get("prepay_id");
        
        if(null == prepayid || "".equals(prepayid)){
            //请求微信异常，返回空
            return null;
        }
        
        log.info("WeChatPayment.wapCreateDeepLink prepayid:" + prepayid);
        
        //生成deeplink,封装h5页面调用参数
        Map<String , Object> signMap = new HashMap<String , Object>();
        //随机字符串
        String nonceStr = RandomStringGenerator.getRandomStringByLength(32);
        //时间戳
        long timestamp = System.currentTimeMillis() / 1000;
        //公众账号ID
        signMap.put("appId", appid);
        //随机字符串
        signMap.put("nonceStr", nonceStr);
        //扩展字段，固定填写WAP
        signMap.put("package", "WAP");
        //微信统一下单接口返回的预支付回话标识，用于后续接口调用中使用，该值有效期为2小时
        signMap.put("prepayid", prepayid);
        //时间戳
        signMap.put("timeStamp", timestamp + "");
        //签名
        String paySign2 = WeChatSignature.getSign(signMap, signKey);
        signMap.put("sign", paySign2);
        
        //生成deeplink地址
        return WeChatDeepLink.createDeepLink(signMap);
    }
    
    /**
     * 通过网页（电脑网页）进行充值，提交到第三方的充值订单信息（微信支付暂无网页支付）
     * 
     * @param paymentChargeOrder 充值信息
     * @return 跳转网关的url串
     * @throws Exception
     * 2016年6月3日 by lh.qiu
     */
    @Override
	public String chargeByWeb(PaymentChargeOrder paymentChargeOrder)
			throws Exception {
    	
    	// 商户号
		String channelUser = paymentChargeOrder.getChannelUser();
		// 题目
		String title = paymentChargeOrder.getTitle();
		//  明细
		String detail = paymentChargeOrder.getDetail();
		// 订单号
		String orderId = paymentChargeOrder.getOrderId();
		// 金额
		double money = paymentChargeOrder.getMoney();
		// 加密key
		String signKey = paymentChargeOrder.getSignKey();
		// json配置串
    	String jsonConfig = paymentChargeOrder.getJsonConfig();
    	// 支付地址
		String payUrl = paymentChargeOrder.getPayUrl();
		// 通知地址
		String notifyUrl = paymentChargeOrder.getNotifyUrl();
		
        //金额格式化
        DecimalFormat df  = new DecimalFormat("#");
        //获取prepayid
        Map<String , Object> map = new HashMap<String , Object>();
        
        //个性化配置
        JSONObject jsonObject =  JsonUtils.fromJson(jsonConfig);
        String appid = jsonObject.get("appid").toString();
        String spbillCreateIp = jsonObject.get("spbillCreateIp").toString();
        
        //String notifyUrl = cpc.getNotifyUrl() + "/" + ccr.getPlatId() + "/" + cpc.getPayChannelId();
        
        map.put("appid", appid);
        //微信支付分配的商户号
        map.put("mch_id", channelUser);
        
        //随机字符串，不长于32位
        map.put("nonce_str", RandomStringGenerator.getRandomStringByLength(32));
        //商品或支付单简要描述
        map.put("body", title);
        //商品详情
        map.put("detail", detail);
        //商户系统内部的订单号,32个字符内
        map.put("out_trade_no", orderId);
        //订单总金额，单位为分
        map.put("total_fee", df.format(money * 100));
        //Native支付填调用微信支付API的机器IP
        map.put("spbill_create_ip", spbillCreateIp);
        //接收微信支付异步通知回调地址，通知url必须为直接可访问的url，不能携带参数
        map.put("notify_url", notifyUrl);
        //交易类型
        map.put("trade_type", WeChatConst.TRADE_TYPE_NATIVE);
        //此id为二维码中包含的商品ID,购彩只有一种商品为彩票
        map.put("product_id", orderId);
        
        //map.put("openid", openid);
        
        //对请求参数签名
        String paySign = WeChatSignature.getSign(map, signKey);
        //对请求参数签名
        map.put("sign", paySign);
        
        //请求返回xml
        //String unifiedOrderResult = new HttpsCerRequest().sendPost(payUrl + WeChatConst.TRADE_URL_UNIFIEDORDER, map);
        String postDataXML = XMLUtil.mapToXml(map);
        String unifiedOrderResult = HttpsRequestUtil.httpsRequestToString(payUrl + WeChatConst.TRADE_URL_UNIFIEDORDER, "POST", postDataXML);
        
        log.info("wechat https request:" + unifiedOrderResult);
        
        Map<String, Object> unifiedOrderMap = XMLUtil.parse(unifiedOrderResult.getBytes(WeChatConst.TRADE_CHARSET_UTF8));
        
        String return_code = (String)unifiedOrderMap.get("return_code");
        
        if(null == return_code || WeChatConst.TRADE_FAIL.equals(return_code)){
            //统一下单失败
            log.info("WeChatPayment.webCreateDeepLink return_code:" + return_code + 
                    ",return_msg:" + unifiedOrderMap.get("return_msg"));
            return null;
        }
        
        //业务结果
        String result_code = (String)unifiedOrderMap.get("result_code");
        
        if(null == result_code || WeChatConst.TRADE_FAIL.equals(result_code)){
            //统一下单失败
            log.info("WeChatPayment.webCreateDeepLink err_code:" + unifiedOrderMap.get("err_code") + 
                    ",err_code_des:" + unifiedOrderMap.get("err_code_des"));
            return null;
        }
        
        //二维码链接
        String code_url = (String)unifiedOrderMap.get("code_url");
        
        if(null == code_url || "".equals(code_url)){
            //请求微信异常，返回空
            return null;
        }
        
        log.info("WeChatPayment.webCreateDeepLink code_url:" + code_url);
        
        return code_url;
    }
    
    /**
     * 通过手机网页进行充值，提交到第三方的充值订单信息（生成微信扫码支付的二维码链接地址）
     * 
     * @param paymentChargeOrder 充值信息
     * @return 跳转网关的url串
     * @throws Exception
     * 2016年6月3日 by lh.qiu
     */
	@Override
	public String chargeByWap(PaymentChargeOrder paymentChargeOrder)
			throws Exception {
		return null;
	}
}
